package com.futurescale.sa.model.vo
{
	import com.futurescale.sa.model.enum.StoryTypeEnum;

	/**
	 * A Series may contain one or more Episodes (Stories). 
	 * Those Episodes may optionally be grouped by Season. 
	 * This value object represents a Series and all its
	 * associated Seasons, Episodes, Cast, Milieu and Plots.
	 */
	[Bindable] 
	public class SeriesVO extends ValueObject
	{
		/**
		 * The XML element name.
		 */
		public static const ELEMENT:String = "Series";
		
		/**
		 * Construct a SeriesVO.
		 */
		public function SeriesVO( xml:XML=null )
		{
			super( ELEMENT, xml );
		}
				
		/**
		 * The Cast.
		 */ 
		public function get cast():CastVO
		{
			return ( x.Cast[0] )?new CastVO( x.Cast[0] ):null;
		}
		public function set cast( c:CastVO ):void
		{
			x.Cast = c.xml;
		}
		
		/**
		 * The Milieu.
		 */ 
		public function get milieu():MilieuVO
		{
			return ( x.Milieu[0] )?new MilieuVO( x.Milieu[0] ):null;
		}
		public function set milieu( m:MilieuVO ):void
		{
			x.Milieu = m.xml;
		}
		
		/**
		 * Will Seasons be used to group Episodes 
		 * in this Series?
		 */ 
		public function get useSeasons():Boolean
		{
			return (x.@useSeasons=="true");
		}
		public function set useSeasons(u:Boolean):void
		{
			x.@useSeasons = u;
		}
		
		/**
		 * Story type to be used for each new Story.
		 * StoryTypeEnum.SIMPLE  = Scenes only (the default if using seasons)
		 * StoryTypeEnum.NORMAL  = Chapters, and Scenes (the default if not using seasons)
		 * StoryTypeEnum.COMPLEX = Parts, Chapters, and Scenes 
		 */ 
		public function get storyType():StoryTypeEnum
		{
			var defaultType:StoryTypeEnum = (useSeasons) ? StoryTypeEnum.SIMPLE : StoryTypeEnum.NORMAL;
			return ( x.@storyType!=undefined ) ? StoryTypeEnum.list[ Number( x.@storyType ) ] : defaultType; 
		}
		public function set storyType( t:StoryTypeEnum ):void
		{
			x.@storyType = t.ordinal;
		}
		
		/** 
		 * An ordinal-sorted Vector of this Series' Seasons,
		 * if used.
		 */
		public function get seasons():Vector.<SeasonVO>
		{
			var v:Vector.<SeasonVO> = new Vector.<SeasonVO>();
			if (useSeasons) {
				var xl:XMLList = xml.child(SeasonVO.ELEMENT);
				for each ( var sx:XML in xl ) {
					var season:SeasonVO = new SeasonVO(sx);
					v.push(season);
				}
				v.sort(ValueObject.ordinalSort);
			}
			return v;
		}
		public function set seasons( v:Vector.<SeasonVO> ):void
		{} // read-only but bindable
		
		/** 
		 * An ordinal-sorted Vector of this Series' 
		 * Stories.
		 */
		public function get stories():Vector.<StoryVO>
		{
			var v:Vector.<StoryVO> = new Vector.<StoryVO>();
			var xl:XMLList = xml..Story;
			for each ( var sx:XML in xl ) {
				var story:StoryVO = new StoryVO(sx);
				v.push(story);
			}
			v.sort(ValueObject.ordinalSort);
			return v;
		}
		public function set stories( v:Vector.<StoryVO> ):void 
		{} // read-only but bindable
		
		/**
		 * Get a new Season for the Series.
		 */
		public function getNewSeason():SeasonVO
		{
			var season:SeasonVO = new SeasonVO();
			season.storyType    = storyType;
			addSeason( season );
			season.getNewStory();
			return season;
		}
		
		/**
		 * Get a new Story for the Series.
		 */
		public function getNewStory( ):StoryVO
		{
			var story:StoryVO = new StoryVO();
			story.type 		  = storyType;
			addStory( story );
			return story;
		}
		
		/**
		 * Add a Story to the Series, renumbering the existing
		 * stories if the added story already has an ordinal less
		 * than the next story ordinal.
		 * 
		 * Forces useSeasons to false.
		 * Sets Series, Cast, and Milieu stubs on Story
		 */
		public function addStory( story:StoryVO ):void
		{
			story.series    = new SeriesVO( this.getStub() );
			story.cast      = cast;
			story.milieu    = milieu;
			
			if ( story.ordinal > 0 && story.ordinal < nextStoryOrdinal ) {
				var stories:Vector.<StoryVO> = this.stories;
				for each (var svo:StoryVO in stories ){
					if (svo.ordinal >= story.ordinal) svo.ordinal = svo.ordinal+1;
				}
			} else {
				story.ordinal = nextStoryOrdinal;
			}
			xml.appendChild( story.xml );
			useSeasons = false;
		}
		
		/**
		 * Add a season to the series, renumbering the existing
		 * seasons if the added story already has an ordinal less
		 * than the next season ordinal. 
		 * 
		 * Forces useSeasons to true. 
		 */
		public function addSeason( season:SeasonVO ):void
		{
			season.series    		= new SeriesVO( this.getStub() );
			season.series.cast		= cast;
			season.series.milieu    = milieu;
			
			if ( season.ordinal > 0 && season.ordinal < nextSeasonOrdinal ) {
				var seasons:Vector.<SeasonVO> = this.seasons;
				for each (var svo:SeasonVO in seasons ){
					if (svo.ordinal >= season.ordinal) svo.ordinal = svo.ordinal+1;
				}
			} else {
				season.ordinal = nextSeasonOrdinal;
			}
			xml.appendChild( season.xml );	
			useSeasons=true;
		}
		
		/**
		 * Get the next Story ordinal for this Series.
		 */
		public function get nextStoryOrdinal():Number
		{
			return getNextOrdinal( xml..Story );
		}

		/**
		 * Get the next Season ordinal for this Series.
		 */
		public function get nextSeasonOrdinal():Number
		{
			return getNextOrdinal( xml..Season );
		}
	}
}